home *** CD-ROM | disk | FTP | other *** search
- /*
- * Blob Manager Demonstration: Pyramid module
- *
- * This is played on a checkerboard. Each player has 10 pieces
- * arranged in a pyramid. Moves are into adjacent diagonal squares,
- * in either direction. Jumps are also allowed, over either side's
- * pieces. The first player to reassemble a pyramid on the side
- * opposite to that which he started on wins.
- *
- * I haven't thought about deadlock detection yet. Probably never will.
- *
- * 11 August 1986 Paul DuBois
- *
- * 24 Dec 93
- * - First two arguments to DrawBoardPos() were reversed.
- * - Changed DrawBoardPos() to use RGB gray for dimmed positions when
- * possible.
- */
-
- # include "TransSkel.h"
-
-
- # include "BlobMgr.h"
- # include "BlobDemo.h"
-
-
- # define rows 8 /* number of rows on board */
- # define columns 8 /* number of columns on board */
- # define pieceSize 20 /* size of each piece */
- # define vMessage 165 /* vertical position of message */
-
- # define BoardPos(b,ph,pv) FindCheckerBoardPos(b,&board,ph,pv)
- # define PosEmpty(h,v) CheckerBoardPosEmpty(&board,h,v)
- # define PosFilled(h,v) CheckerBoardPosFilled(&board,h,v)
-
- static WindowPtr wind;
-
-
- static BlobSetHandle boardBlobs = nil;
- static CheckerBoard board;
- static BlobSetHandle donors = nil;
- static BlobHandle current;
- static BlobHandle pBlack;
- static BlobHandle pWhite;
- static BlobHandle lastXferPiece;
- static Boolean lastWasJump;
- static BlobSetHandle misc;
- static BlobHandle resetBlob; /* simulated control */
-
- static short hMid;
- static Boolean paused;
- static Str255 statusStr = "\p";
-
- /*
- * Initial configuration
- */
-
- static short layout[rows][columns] = /* 0 = black, 1 = white, 2 = none */
- {
- 0, 2, 2, 2, 2, 2, 2, 2,
- 2, 0, 2, 2, 2, 2, 2, 1,
- 0, 2, 0, 2, 2, 2, 1, 2,
- 2, 0, 2, 0, 2, 1, 2, 1,
- 0, 2, 0, 2, 1, 2, 1, 2,
- 2, 0, 2, 2, 2, 1, 2, 1,
- 0, 2, 2, 2, 2, 2, 1, 2,
- 2, 2, 2, 2, 2, 2, 2, 1
- };
-
-
- static void
- StatusMesg (StringPtr s)
- {
- Rect r;
-
- SetRect (&r, 0, vMessage, wind->portRect.right - 25, vMessage + 12);
- TextBox (s+1, (long) s[0], &r, teJustCenter);
- StrCpy (statusStr, s);
- }
-
-
- /*
- * Set the board to the initial configuration
- */
-
- static void
- Reset (void)
- {
- short i, j, val;
- BlobHandle b;
-
- UnglueGlobSet (boardBlobs); /* clear all globs */
- for (i = 0; i < columns; ++i)
- {
- for (j = 0; j < rows; ++j)
- {
- val = layout[i][j];
- b = board[i][j];
- DisposeBlobMatchSet (b);
- if (val != 2)
- {
- GlueGlob (GetBlobHandle (donors, val), b);
- NewBlobMatch (GetBlobHandle (donors, 1 - val), b);
- }
- }
- }
- current = pWhite;
- StatusMesg ("\p");
- paused = false;
- lastWasJump = false; /* last move wasn't a jump */
- }
-
-
- static void
- Pause (StringPtr msg)
- {
- StatusMesg (msg);
- paused = true;
- }
-
-
- /*
- * Test whether a piece can move or not. It can move if there's an
- * empty adjacent diagonal, or a piece adjacent with an empty square
- * on the other side of it. If the last move was a jump, and the
- * piece is the same one that jumped, then can only move if can
- * keep jumping.
- */
-
- static Boolean
- CanMove (short h, short v)
- {
- if ( (PosFilled (h - 1, v - 1) && PosEmpty (h - 2, v - 2))
- || (PosFilled (h + 1, v - 1) && PosEmpty (h + 2, v - 2))
- || (PosFilled (h - 1, v + 1) && PosEmpty (h - 2, v + 2))
- || (PosFilled (h + 1, v + 1) && PosEmpty (h + 2, v + 2)))
- return (true);
-
- if (board[h][v] == lastXferPiece && lastWasJump)
- return (false);
-
- return ( PosEmpty (h - 1, v - 1)
- || PosEmpty (h + 1, v - 1)
- || PosEmpty (h - 1, v + 1)
- || PosEmpty (h + 1, v + 1) );
- }
-
-
- /*
- * Test for a win. Pass the upper and lower limits on the rows to
- * test (either the top or botton half of the board).
- */
-
- static Boolean
- TestWin (short loRow)
- {
- short i, j;
- MatchHandle m;
-
- for (i = loRow; i < loRow + rows / 2; ++i)
- {
- for (j = 0; j < columns; ++j)
- {
- if ((m = (**board[j][i]).matches) != nil
- && BGlob (board[j][i]) != (**m).mBlob)
- return (false); /* at least one mismatch */
- }
- }
- return (true);
- }
-
-
- /*
- * When a piece is clicked on, the advisory checks whether the piece has
- * any legal moves available to it. If so, it returns true, so that
- * BlobClick is allowed to drag the piece. After the piece has been
- * dragged, the advisory checks whether the position it was dragged to
- * is legal, and returns true if so.
- *
- * Messages passed to the advisory follow the pattern
- *
- * { { advRClick advRClick* } advXfer* }*
- *
- * where * means 0 or more instances of the thing *'ed. In particular,
- * the advXfer message is never seen without a preceding advRClick.
- */
-
- static pascal Boolean
- Advisory (short mesg, BlobHandle b)
- {
- static short h, v; /* static to save board position of click on piece */
- short h2, v2;
- Boolean result;
-
- switch (mesg)
- {
-
- case advRClick: /* first click on piece */
- if (BGlob (b) != current && !(b == lastXferPiece && lastWasJump))
- return (false);
- BoardPos (b, &h, &v); /* find where it is */
- return (CanMove (h, v));
-
- case advXfer: /* Mouse released after dragging piece */
-
- BoardPos (b, &h2, &v2);
- result = (h2 == h - 1 || h2 == h + 1)
- && (v2 == v - 1 || v2 == v + 1);
- if (result == true)
- lastWasJump = false;
- else
- {
- result = (h2 == h - 2 || h2 == h + 2)
- && (v2 == v - 2 || v2 == v + 2)
- && PosFilled ((h + h2) / 2, (v + v2) / 2);
- if (result == true)
- lastWasJump = true;
- }
- if (result == true)
- lastXferPiece = b;
- return (result);
- }
- }
-
-
- static pascal void
- Mouse (Point pt, long t, short mods)
- {
- if (TestBlob (resetBlob, pt))
- {
- if (BTrackMouse (resetBlob, pt, inFullBlob))
- Reset ();
- }
- else if (!paused)
- {
- BlobClick (pt, t, nil, boardBlobs);
- if (BClickResult () == bcXfer)
- {
- if (TestWin (0))
- Pause ("\pWhite Wins");
- else if (TestWin (rows / 2))
- Pause ("\pBlack Wins");
- else if (BGlob (lastXferPiece) == current) /* switch if didn't move prev player */
- current = (current == pBlack ? pWhite : pBlack);
- }
- }
- }
-
-
- static pascal void
- Update (Boolean resized)
- {
- DrawBlobSet (boardBlobs);
- DrawBlobSet (misc);
- StatusMesg (statusStr);
- }
-
-
- /*
- * Activate the window: Set the advisory function and set the permissions
- * to transfer-only. Clear, replace, duplication and swap are off.
- * Since replace is off, the advisory doesn't have to check whether
- * the dragged piece was dragged onto a blob that already has a glob.
- *
- * Deactivate the window: Clear the advisory.
- */
-
- static pascal void
- Activate (Boolean active)
- {
- if (active)
- {
- SetDragRects (wind);
- SetBCPermissions (false, true, false, false, false); /* xfer only */
- SetBCAdvisory (Advisory);
- }
- else
- {
- SetBCAdvisory (nil);
- }
- }
-
-
- void
- PyrInit (void)
- {
- Rect r;
-
- SkelWindow (wind = GetDemoWind (pyrWindRes),
- Mouse, /* mouse clicks */
- nil, /* key clicks */
- Update, /* updates */
- Activate, /* activate/deactivate events */
- nil, /* close window */
- DoWClobber, /* dispose of window */
- nil, /* idle proc */
- false); /* irrelevant, since no idle proc */
-
- hMid = wind->portRect.right / 2;
-
-
- donors = MakeCheckersPieces (pieceSize);
- pBlack = GetBlobHandle (donors, 0);
- pWhite = GetBlobHandle (donors, 1);
- MakeCheckerBoard(&boardBlobs, &board, pieceSize);
- misc = NewBlobSet ();
- SetRect (&r, 0, 0, 20, 90);
- OffsetRect (&r, wind->portRect.right - 25,
- (wind->portRect.bottom - 90 - 25) / 2);
- resetBlob = NewVButtonBlob (misc, &r, "\pReset", true);
- Reset ();
-
- MakeFrontWind (wind);
- }
-